package com.github.ghsea.scheduler.core;

import com.github.ghsea.scheduler.entity.TaskSchedulerEntity;
import com.github.ghsea.scheduler.service.TaskSchedulerService;
import com.github.ghsea.scheduler.util.RunnableDelegate;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author guhai
 * @since 2021/6/17 22:28
 * <p>
 * 查找心跳超时的server，并接管该server对应的task
 */
@Component
@Slf4j
public class DatabaseHaTaskScheduler extends TaskScheduler implements ApplicationListener<ApplicationReadyEvent> {

    @Resource(name = "scheduledExecutor")
    private ScheduledExecutorService scheduledExecutor;

    @Resource
    private TaskSchedulerService taskSchedulerService;

    private ConcurrentHashMap<String, Boolean> switchingServer = new ConcurrentHashMap<>();

    private void monitorAndDiscovery() {
        TaskSchedulerEntity crashedScheduler = taskSchedulerService.queryCrashedServer();
        if (crashedScheduler == null) {
            return;
        }

        String server = crashedScheduler.getServer();
        if (switchingServer.containsKey(server) || Boolean.TRUE.equals(switchingServer.putIfAbsent(server, true))) {
            return;
        }

        discovery(server);
    }

    private void discovery(String server) {
        log.info("begin to discovery for the crashed server {}.The new server is {}", server, serverName);
        initTaskAndSchedule(server, true);
        log.info("end discovery for the crashed server {}.The new server is {}", server, serverName);
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        scheduledExecutor.scheduleAtFixedRate(new RunnableDelegate(() -> monitorAndDiscovery()),
                5, HEARTBEAT_INTERVAL_SECONDS, TimeUnit.SECONDS
        );
    }
}
